package com.lipaluma.field.validator.impl.generic;

import java.util.List;

import com.lipaluma.field.validator.Resetable;
import com.lipaluma.field.validator.ValidationError;
import com.lipaluma.field.validator.Validator;

/**
 * Validator that ckeck if the entry value is constant.<br/>
 * If no value is defined, the process takes the first value encountered to check the constance.
 * <p>
 * To initialize Constant Validator : 
 * <ul>
 * <li>With annotation : add {@link Constant} annotation to the field</li>
 * <li>on xml file : add element <code>&lt;constant value="value" pattern="pattern"/></code> in <code>&lt;column></code> element<br/>
 * the attribute value is optional.<br/>
 * Also, the attribute pattern is optional except the case where constant is filled and is a date constant.</li>
 * </ul>
 * 
 * @author Mario<br/>
 * <br/>
 * <b>The code in inspired by : </b>
 * @author Dominique De Vito from super-csv
 * @author James Bassett from super-csv
 */
public abstract class AbstractConstantValidator<T> implements Validator, Resetable {
	public static final Object UNKNOWN = new Object();

	private Object constant = UNKNOWN;
	private boolean constantSupplied = false;
	
	public AbstractConstantValidator() {
		constantSupplied = false;
	}
	public AbstractConstantValidator(T constant) {
		constantSupplied = true;
		this.constant = constant;
	}
	
	protected void init(T constant) {
		constantSupplied = true;
		this.constant = constant;
	}
	
	public boolean validate(Object value, List<ValidationError> errors) {
		if( UNKNOWN.equals(constant) )
			constant = value;
		if(!equals(constant, value)) {
			if(constantSupplied)
				errors.add(new ValidationError("The constant supplied "+constant+" is not equal to the value "+value));
			else 
				errors.add(new ValidationError("The value "+value+" is not equal to the previous value "+constant));
			return false;
		}
		return true;
	}

	private static boolean equals(Object o1, Object o2) {
		return (o1 == null) ? (o2 == null) : o1.equals(o2);
	}
	
	@Override
	public void reset() {
		if(!constantSupplied)
			this.constant = UNKNOWN;
	}
}
